package cn.amossun.starter.api.data.security.rewrite;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.amossun.starter.api.data.security.rule.ApiDecryptRule;
import cn.amossun.starter.common.annotation.DataSecurity;
import cn.amossun.starter.common.enums.DesensitizedType;
import cn.amossun.starter.common.util.ClassUtil;
import cn.amossun.starter.common.util.DesensitizedExecutor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * @description:
 * @author: Amos.Sun
 * @DateTime: 2020/03/01 15:14
 **/
@Data
@Slf4j
@NoArgsConstructor
@AllArgsConstructor
public class DecryptObjectRewriter {

    private ApiDecryptRule apiDecryptRule;

    /**
     * 基本数据类型和String类型判断
     */
    public boolean isPrimitive(Class<?> clz) {
        try {
            return ClassUtil.isPrimitive(clz);
        } catch (Exception e) {
            log.error("判断对象是否为jdk基本类型时异常: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 对象数据解密脱敏
     * @param object
     * @return
     */
    public void rewriter(Object object) throws IllegalAccessException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, UnsupportedEncodingException {
        if (null == object) {
            return;
        }

        //如果是原始类型，则忽略处理
        if (object.getClass().isPrimitive()) {
            return;
        }
        // 是否是接口
        if (object.getClass().isInterface()) {
            return;
        }

        Class<?> clazz = object.getClass();

        // 获取所有属性
        List<Field> classFieldList = ClassUtil.getAllClassFields(clazz);

        if (CollectionUtil.isEmpty(classFieldList)) {
            return;
        }
        processFields(object, classFieldList);
    }

    /**
     * 对象字段解密脱敏
     * @param object
     * @param classFieldList
     * @throws IllegalAccessException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    protected void processFields(Object object, List<Field> classFieldList) throws IllegalAccessException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, UnsupportedEncodingException {
        for (Field field : classFieldList) {
            if (null == field) {
                continue;
            }
            field.setAccessible(true);

            Object value = field.get(object);
            if (null != value) {
                Class<?> type = value.getClass();

                //如果是通用的分页响应对象，则对该对象内部的List<T>进行脱敏
                // 1.处理子属性，包括集合中的
                if (type.isArray()) {
                    int len = Array.getLength(value);
                    for (int i = 0; i < len; i++) {
                        Object arrayObject = Array.get(value, i);
                        rewriter(arrayObject);
                    }
                } else if (value instanceof Collection<?>) {
                    Collection<?> c = (Collection<?>) value;
                    Iterator<?> it = c.iterator();
                    while (it.hasNext()) {
                        Object collectionObj = it.next();
                        rewriter(collectionObj);
                    }
                } else if (value instanceof Map<?, ?>) {
                    Map<?, ?> m = (Map<?, ?>) value;
                    Set<?> set = m.entrySet();
                    for (Object o : set) {
                        Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
                        Object mapVal = entry.getValue();
                        rewriter(mapVal);
                    }
                } else if (!type.isPrimitive()
                        && !StrUtil.startWith(type.getPackage().getName(), "javax.")
                        && !StrUtil.startWith(type.getPackage().getName(), "java.")
                        && !StrUtil.startWith(field.getType().getName(), "javax.")
                        && !StrUtil.startWith(field.getName(), "java.")) {
                    rewriter(value);
                } else if (String.class.equals(field.getType()) || Number.class.equals(field.getType())) {
                    // 2.处理自身属性
                    DataSecurity dataSecurityAnnotation = field.getDeclaredAnnotation(DataSecurity.class);
                    processField(object, field, dataSecurityAnnotation);
                }

            }
        }
    }

    /**
     * 字段解密脱敏
     * @param object
     * @param field
     * @param dataSecurity
     * @throws IllegalAccessException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    protected void processField(Object object, Field field, DataSecurity dataSecurity) throws IllegalAccessException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, UnsupportedEncodingException {
        if (null != dataSecurity && (dataSecurity.decrypt() || dataSecurity.desensitizedType() != DesensitizedType.DEFAULT_SKIP)) {

            String objectValue = String.valueOf(field.get(object));
            if (StrUtil.isNotBlank(objectValue)) {

                if(StrUtil.isNotEmpty(dataSecurity.delimiter())) {
                    field.set(object, delimiterHandler(dataSecurity, objectValue));
                    return;
                }

                if(dataSecurity.decrypt()) {  //解密处理
                    objectValue = apiDecryptRule.genericDecryptValue(objectValue);
                }

                if(dataSecurity.desensitizedType() != DesensitizedType.DEFAULT_SKIP) { //脱敏处理
                    objectValue = DesensitizedExecutor.desensitized(dataSecurity.desensitizedType(), objectValue);
                }

                field.set(object, objectValue);
            }
        }


    }

    protected String delimiterHandler(DataSecurity dataSecurity, String originalValue) throws BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, UnsupportedEncodingException {
        List<String> originalValueList = Arrays.asList((String.valueOf(originalValue)).split(dataSecurity.delimiter()));
        List<String> delimiterHandlerList = new ArrayList<>(originalValueList.size());
        for (String source : originalValueList) {
            if(dataSecurity.decrypt()) {  //解密处理
                source = apiDecryptRule.genericDecryptValue(source);
            }
            if(dataSecurity.desensitizedType() != DesensitizedType.DEFAULT_SKIP) { //脱敏处理
                source = DesensitizedExecutor.desensitized(dataSecurity.desensitizedType(), source);
            }
            delimiterHandlerList.add(source);
        }
        return StrUtil.join(dataSecurity.delimiter(), delimiterHandlerList);
    }

}
